﻿using System;
using System.Net.Mail;
using System.Web.Mvc;
using Common.Password;
using ContactMvc4TB.Helpers.HelperClasses;
using EFDataModel;

namespace ContactMvc4TB.Helpers.MailManagement
{
    /// <summary>
    /// Das Zurücksetzten des Passwortes Per EMail
    /// </summary>
    public class PasswordRecoveryMail
    {
        #region Properties
        /// <summary>
        /// Der Aktuelle CurrentController für Messages z.b.
        /// </summary>
        private Controller CurrentController { get; set; }
        #endregion

        #region Konstruktor
        /// <summary>
        /// Inistialiseren der PasswordRecovery
        /// </summary>
        /// <param name="controller">der Aktuelle CurrentController</param>
        public PasswordRecoveryMail(Controller controller)
        {
            CurrentController = controller;
        }
        #endregion

        /// <summary>
        /// Die Passwort Wiederherstellung für den User beginnen der hier übergeben wird.
        /// </summary>
        /// <param name="efUser"></param>
        /// <returns>TRUE->Mail konnte erfolgreich versendet werden | FALSE->Fehler beim Versenden der EMail</returns>
        public bool InitPasswordRecovery(EFUser efUser)
        {
            //Datum setzen an dem das PW zurück gesetzt wird und den User abspeichern
            efUser.PasswordResetDate = DateTime.Now;
            CurrentHttpContext.GetDataModel().SaveChanges();

            //der Hashwert der in der Mail als Link übermittelt wird setzt sich aus dem Usernamen und dem PasswordResetDate zusammen.
            //Damit kann später geprüft werden ob der Reset auch vom richtigen User durchgeführt werden soll
            string mailHash = PasswordHash.GetPasswordHash(efUser.LoginEmail, efUser.PasswordResetDate.Value.ToString(EFUser.PasswordDateFormat), EFUser.HashCount);

            try
            {
                //Erstellen einer neuen URL im codebehinde
                string url = CurrentController.Url.Action(EActionAccount.NewPasswordSend.ToString(), EControllers.Account.ToString(), new {id = efUser.ID, hash = mailHash}, WebConstants.ProtocollType);
                //Zusammenbauen der passenden Maildaten
                string mailMessage = string.Format(GlobalResources.Mailformulars.PasswordRecoveryHashMailRESX, url);
                //Kontaktaufnahme von: {0} - {1}
                string subject = string.Format(GlobalResources.Mailformulars.PasswordRecoveryHashSubjectRESX, efUser.LoginEmail);

                MailMessage message = new MailMessage();
                message.Subject = subject;
                message.Body = mailMessage;
                message.To.Add(new MailAddress(efUser.LoginEmail));

                //Der SMTP Client liest die Mail Credentials direkt aus der Web.Config aus.
                SmtpClient client = new SmtpClient();
                client.Send(message);
                return true;
            }
            catch (Exception ex)
            {
                EFDebugging.Debugging.WriteLog("SendMail für InitPasswordRecovery: ", ex);
            }

            return false;
        }

        /// <summary>
        /// Setzten eines neuen Passwortes für den Account, der übergeben wurde und versenden des neuen Passworts an den User.
        /// </summary>
        /// <param name="userId">Der User für den das Passwort zurückgesetzt werden soll</param>
        /// <param name="hash">der Hashcode zum überprüfen ob das passwort auch für diesen Account zurück gesetzt werden soll</param>
        /// <returns>TRUE->Erfolgreich zurückgesetzt | FALSE->Fehler beim Zurücksetzten des Passworts</returns>
        public bool SetNewPassword(int userId, string hash)
        {
            //Den User heraussuchen der übergeben wurde.
            EFUser efUser = (EFUser)CurrentHttpContext.GetDataModel().EFBaseMenge.Find(userId);
            if (efUser != null)
            {
                //Prüfen ob überhaupt ein PasswordReset angefordert wurde oder ob er bereits eingelöst wurde.
                if (efUser.PasswordResetDate.HasValue)
                {
                    //Die Hashdaten wieder erstellen und prüfen ob diese mit den Daten aus der URL übereinstimmen
                    string accountHash = PasswordHash.GetPasswordHash(efUser.LoginEmail, efUser.PasswordResetDate.Value.ToString(EFUser.PasswordDateFormat), EFUser.HashCount);
                    if (accountHash == hash)
                    {
                        
                        //Prüfen ob der Link noch gültig ist, denn dieser ist nur 24 Stunden gültig.
                        if (DateTime.Now < efUser.PasswordResetDate.Value.AddHours(24))
                        {
                            //Es ist der richtige User für den das Passwort wiederhergestellt werden soll
                            string newPassword = PasswordHash.GetRandomString(WebConstants.PasswordLength, false);
                            //Das PW Reset Date zurücksetzten und das Passwort neu setzten
                            efUser.PasswordResetDate = null;
                            efUser.SetPassword(newPassword);

                            //Als erstes die Mail versenden, denn wenn etwas schief geht beim Mailversenden, dann nicht die Daten des Users speichern.
                            try
                            {
                                //Zusammenbauen der passenden Maildaten
                                string mailMessage = string.Format(GlobalResources.Mailformulars.NewPasswordSendMailRESX, newPassword);
                                //Kontaktaufnahme von: {0} - {1}
                                string subject = string.Format(GlobalResources.Mailformulars.NewPasswordSendSubjectRESX, efUser.LoginEmail);

                                MailMessage message = new MailMessage();
                                message.Subject = subject;
                                message.Body = mailMessage;
                                message.To.Add(new MailAddress(efUser.LoginEmail));

                                //Der SMTP Client liest die Mail Credentials direkt aus der Web.Config aus.
                                SmtpClient client = new SmtpClient();
                                client.Send(message);

                                //Speichern der Einstellungen erst nach dem die Mail problemlos versendet werden konnte.
                                CurrentHttpContext.GetDataModel().SaveChanges();
                                //Erfolgsmeldung ausgeben
                                CustomMessage.CurrentMessage(CurrentController).AddMessage(GlobalResources.SystemMessages.NewPasswordSendedRESX, MessageTypes.ok);

                                return true;
                            }
                            catch (Exception ex)
                            {
                                EFDebugging.Debugging.WriteLog("SendMail für SetNewPassword: ", ex);
                            }
                        }
                    }
                    else
                    {
                        //Der Link ist ungültig, da kein Datum existiert an dem das PW zurück gesetzt werden sollte, evtl. ein bereits benutzter link.
                        CustomMessage.CurrentMessage(CurrentController).AddMessage(GlobalResources.SystemMessages.PasswordRecoveryLinkIsInvalidRESX, MessageTypes.error);
                    }
                }
                else
                {
                    //Der Link ist ungültig, da kein Datum existiert an dem das PW zurück gesetzt werden sollte, evtl. ein bereits benutzter link.
                    CustomMessage.CurrentMessage(CurrentController).AddMessage(GlobalResources.SystemMessages.PasswordRecoveryLinkIsInvalidRESX, MessageTypes.error);
                }
            }
            else
            {
                //Der Benutzer existiert nicht Fehler ausgeben
                CustomMessage.CurrentMessage(CurrentController).AddMessage(GlobalResources.SystemMessages.UserDontExistsErrorRESX, MessageTypes.error);
            }

            return false;
        }

    }
}